#-*- codeing = utf-8 -*-
#@Time : 2020/10/30 16:13
#@Author : 阳某
#@File : 14.Python绘制桑基图分析广告转化数据.py
#@Software : PyCharm


'''
桑基图 (Sankey Diagram)：是一种特定类型的流图，用于描述一组值到另一组值的流向。

桑基图的特点如下：

起始流量和结束流量相同，所有主支宽度的总和与所有分出去的分支宽度总和相等，保持能量的平衡；
在内部，不同的线条代表了不同的流量分流情况，它的宽度成比例地显示此分支占有的流量；
节点不同的宽度代表了特定状态下的流量大小。
'''
# 1. 读取广告转化数据集
import pandas as pd
# 数据源：https://www.kaggle.com/loveall/clicks-conversion-tracking/data
# 广告转化数据集：Ad Conversions Data
df = pd.read_csv("./datas/KAG_conversion_data.csv")
print(df.head(10))
# 绘图目的： 总流量 > 不同的活动 > 性别 > 年龄

# 2. 构造桑基图数据集
# 数据处理
df["total"] = "全量"
df["xyz_campaign_id"] = df["xyz_campaign_id"].map(lambda x : f"campaign_{x}")
df["gender"] = df["gender"].map(lambda x : f"gender_{x}")
df["age"] = df["age"].map(lambda x : f"age_{x}")
print(df.head(10))

# Pyecharts桑基图数据1：节点列表
nodes = pd.concat([df["total"], df["xyz_campaign_id"], df["age"], df["gender"]]).unique()
print(nodes)
# Pyecharts桑基图数据2：节点到达关系列表
type_list = ["total", "xyz_campaign_id", "gender", "age"]
from_to_list = []
for idx in range(len(type_list) - 1):
    from_type = type_list[idx]
    to_type = type_list[idx + 1]
    print(from_type, to_type)

    df_agg = df.groupby([from_type, to_type]).size().reset_index()
    df_agg.columns = ["from", "to", "value"]

    for _, (from_key, to_key, value) in df_agg.iterrows():
        from_to_list.append([from_key, to_key, value])

print(from_to_list)
# 中间步骤的解释：计算相邻节点的from和to
df_agg = df.groupby(["total", "xyz_campaign_id"]).size().reset_index()
df_agg.columns = ["from", "to", "value"]
print(df_agg)


# 3. 绘制桑基图
#
# # 1. 转换节点列表为桑基图形式
pyecharts_nodes = [{"name": node} for node in nodes]
print(pyecharts_nodes)

# 2. 转换跳转列表为桑基图形式
pyecharts_links = [
            {"source": source, "target": target, "value": value}
            for source, target, value in from_to_list
        ]
print(pyecharts_links)
from pyecharts import options as opts
from pyecharts.charts import Sankey

sankey = (
    Sankey()
    .add(
        "",
        pyecharts_nodes,
        pyecharts_links,
        linestyle_opt=opts.LineStyleOpts(opacity=0.2, curve=0.5, color="source"),
        label_opts=opts.LabelOpts(position="right"),
    )
    .set_global_opts(title_opts=opts.TitleOpts(title="广告转化数据桑基图"))
)

sankey.render_notebook()